package com.neusoft.neuiotms.dcam.fixed.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.transaction.Transactional;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcam.fixed.converter.InventoryPlanConverter;
import com.neusoft.neuiotms.dcam.fixed.converter.InventoryResultConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryPlanDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryResultDTO;
import com.neusoft.neuiotms.dcam.fixed.model.InventoryDuty;
import com.neusoft.neuiotms.dcam.fixed.model.InventoryPlan;
import com.neusoft.neuiotms.dcam.fixed.model.enums.InventoryDutyStatus;
import com.neusoft.neuiotms.dcam.fixed.model.enums.InventoryPlanStatus;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryDutyRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryPlanRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryPlanService;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryResultService;

@Service
public class InventoryPlanServiceImpl implements InventoryPlanService {

    @Autowired
    private InventoryPlanRepository inventoryPlanRepository;
    @Autowired
    private InventoryPlanConverter inventoryPlanConverter;
    @Autowired
    private AssetService assetService;
    @Autowired
    private InventoryResultService inventoryResultService;
    @Autowired
    private InventoryResultConverter inventoryResultConverter;
    @Autowired
    private InventoryDutyRepository inventoryDutyRepository;

    @Override
    public List<InventoryPlanDTO> findAll(final Searchable searchable) {
        final List<InventoryPlan> models = this.inventoryPlanRepository.search(searchable);
        return this.inventoryPlanConverter.toListDTO(models);
    }

    @Override
    public Page<InventoryPlanDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<InventoryPlan> models = this.inventoryPlanRepository.search(pageable, searchable);
        return this.inventoryPlanConverter.toPageDTO(models);
    }

    @Override
    public InventoryPlanDTO create(final InventoryPlanDTO dto) {

        InventoryPlan model = this.inventoryPlanConverter.toModel(dto);

        model = this.inventoryPlanRepository.save(model);

        return this.inventoryPlanConverter.toDTO(model);
    }

    @Override
    public InventoryPlanDTO details(final Long id) {
        final InventoryPlan model;
        try {
            model = this.inventoryPlanRepository.getOne(id);

            if (CollectionUtils.isEmpty(model.getDutyItems())) {
                final Optional<InventoryPlan> optPlan = this.inventoryPlanRepository.findById(id);
                if (optPlan != null) {
                    final InventoryPlan plan = optPlan.get();

                    if ((plan != null) && CollectionUtils.isNotEmpty(plan.getDutyItems())) {
                        model.setDutyItems(plan.getDutyItems().subList(0, plan.getDutyItems().size()));
                    }
                }
            }

        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        return this.inventoryPlanConverter.toDTO(model, true);
    }

    @Override
    public void delete(final Long id) {

        final InventoryPlan model;
        try {
            model = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 如果已经下发的计划不能删除
        if (!InventoryPlanStatus.created.equals(model.getStatus())) {
            throw new UnitedException("只有已创建的状态下才能进行删除操作", new Object[] {id });
        }

        // 删除计划
        this.inventoryPlanRepository.deleteById(model.getId());
    }

    @Override
    public InventoryPlanDTO update(final Long id, final InventoryPlanDTO dto) {

        final InventoryPlan checkModel;
        try {
            checkModel = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 如果已经下发的计划不能变更
        if (!InventoryPlanStatus.created.equals(checkModel.getStatus())) {
            throw new UnitedException("只有已创建的状态下才能进行变更操作", new Object[] {id });
        }

        dto.setId(checkModel.getId());
        InventoryPlan model = this.inventoryPlanConverter.toModel(dto);

        model = this.inventoryPlanRepository.save(model);
        return this.inventoryPlanConverter.toDTO(model);
    }

    @Override
    @Transactional
    public void issue(final Long id) {

        final InventoryPlan model;

        try {
            model = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        if ((model.getDutyItems() == null) || (model.getDutyItems().size() <= 0)) {
            throw new UnitedException("计划中不含有任务,不能下发计划!");
        }

        final List<Long> dutyIdList = new ArrayList<>();
        // 查找所有的资产开始下发
        model.getDutyItems().stream().forEach(m -> {
            dutyIdList.add(m.getId());
            final Searchable searchable = new Searchable();

            // 位置
            final List<String> locationCodes =
                    m.getLocations().stream().map(ele -> ele.getCode()).collect(Collectors.toList());
            if ((locationCodes != null) && (locationCodes.size() > 0)) {
                String[] codes = new String[locationCodes.size()];
                codes = locationCodes.toArray(codes);
                searchable.put("locationCodes", codes);
            }

            // 类型
            final List<String> typeCodes =
                    m.getAssetTypes().stream().map(ele -> ele.getCode()).collect(Collectors.toList());
            if ((typeCodes != null) && (typeCodes.size() > 0)) {
                String[] codes = new String[typeCodes.size()];
                codes = typeCodes.toArray(codes);
                searchable.put("assetTypeCodes", codes);
            }

            // 组织机构
            final List<String> orgIds =
                    m.getOrgRelation().stream().map(ele -> ele.getBusinessId()).collect(Collectors.toList());
            if ((orgIds != null) && (orgIds.size() > 0)) {
                String[] codes = new String[orgIds.size()];
                codes = orgIds.toArray(codes);
                searchable.put("orgIds", codes);
            }

            final Page<AssetDTO> pageList = this.assetService.search(Pageable.unpaged(), searchable);

            final List<AssetDTO> list = pageList != null ? pageList.getContent() : new ArrayList<>();

            list.stream().forEach(k -> {

                final InventoryResultDTO dto = this.inventoryResultConverter.toDTO(k, m.getId());
                // 下发资产
                this.inventoryResultService.create(dto);
            });

        });

        for (final Long idl : dutyIdList) {
            // 更新子任务状态
            final InventoryDuty duty = this.inventoryDutyRepository.getOne(idl);
            if (duty != null) {
                duty.setStatus(InventoryDutyStatus.doing);
                this.inventoryDutyRepository.save(duty);
            }
        }

        // 修改计划状态
        model.setStatus(InventoryPlanStatus.issued);
        this.inventoryPlanRepository.save(model);
    }

    @Override
    public void synchronousData(final String ids, final String rule) {
        this.inventoryResultService.synchronousData(ids, rule);

        //        final InventoryPlan model;
        //        try {
        //            model = this.inventoryPlanRepository.getOne(id);
        //        } catch (final Exception e) {
        //            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        //        }
        //
        //        model.setStatus(InventoryPlanStatus.finish);
        //        this.inventoryPlanRepository.save(model);
    }

    @Override
    public void donePlan(final Long id) {
        final InventoryPlan model;

        try {
            model = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 完成计划状态
        model.setStatus(InventoryPlanStatus.finish);
        this.inventoryPlanRepository.save(model);
    }

    @Override
    public List<InventoryPlanDTO> findByStatus(final String status) {
        final List<InventoryPlan> models =
                this.inventoryPlanRepository.findByStatus(InventoryPlanStatus.valueOf(status));
        return this.inventoryPlanConverter.toListDTO(models);
    }

}
